/**
 * @author cloud
 */

var map;
var mapId = "map";
var cursor;
var line;
var editPlaceholder = "<i>Не задано</i>";
var routes;
var state;
var tempPoint = null;
var movedPoints = null;
var highlightedObjects = null;
var route_from, route_to;

function routeEditBinder() {
    var points = line.geometry.getCoordinates();

    var existingPoints = [];
    var len = 0;
    for (var i = 0; i < points.length - 1; i++)
        len += ymaps.coordSystem.geo.getDistance(points[i], points[i + 1]) / 1000;

    route["points"] = [];
    for (var i = 0; i < points.length; i++) {
        var p = null;
        map.geoObjects.each(function (obj) {
            if (obj.properties.get("pType") == "connection" && obj.geometry.getCoordinates() == points[i])
                p = existingPoints[i] = obj;
        });
        if (p) {
            route["points"].push({
                old: true,
                id: p.properties.get("id"),
                location: p.geometry.getCoordinates()
            });
        } else
            route["points"].push({
                old: false,
                id: guid(),
                location: points[i]
            });
    }
    $("#route-length").text(len.toFixed(3));
    $("#route-id").val(route["id"]);
    $("#route-edit-form").dialog("open");
    $("#route-points").text(points.length);
}

function endDrawing() {
    state = null;
    map.events.remove('click', startPolylineDrawing);
    line.editor.stopEditing();
    cursor.remove();
    if (line.geometry.getCoordinates().length == 0)
        return;
    route = {
        "points": line.geometry.getCoordinates(),
        "id": "",
        "cable": $("#route-cable").val()
    };
    $("#end-route").css("display", "none");
    routeEditBinder();
}

function stateChangeHandler(e) {
    var ev = e.originalEvent;
    if (!ev.newDrawing && ev.oldDrawing)
        endDrawing();

}

function startPolylineDrawing(e) {
    if (!e.originalEvent)
        line = createLine([e]);
    else
        line = createLine([e.get("coordPosition")]);
    line.editor.events.add("statechange", stateChangeHandler);
    line.editor.startEditing();
    line.editor.startDrawing();
}

function initMap() {
    map = new ymaps.Map(mapId, {
        center: default_location,
        zoom: default_zoom,
        behaviors: ['default', 'scrollZoom']
    });
    map.controls.add('zoomControl', {
        left: '9px',
        top: '40px'
    });
    var button = new ymaps.control.Button({
        data: {
            // Зададим иконку для кнопки
            image: 'images/route.png',
            // Текст всплывающей подсказки.
            title: 'Нажмите для создания маршрута'
        }
    }, {
        // Зададим опции для кнопки.
        selectOnClick: false
    });
    button.events.add("click", routeButtonClick);
    map.controls.add(button, {top: 5, left: 5});
    map.controls.add('typeSelector', { right: '10px', top: '5px' });
    $("#mapLayer").val(default_layer);
    refreshMap();
}

function routeButtonClick() {
    $("#solver-block").toggle();
    if (!$("#solver-block").is(":visible"))
        clearRoute();
}

function refreshMap(dialog) {
    if (dialog)
        dialog.dialog("close");
    $.ajax({
        method: "POST",
        url: "include/connection_controller.php",
        data: {
            op: "get_routes",
            layer: $("#mapLayer").val()
        }
    }).done(function (response) {
        var routes = JSON.parse(response);
        $("#route_from, #route_to").html("");
        $("#route_from, #route_to").append("<option value='0'>Не выбрано</option>");
        clearRoute();
        map.geoObjects.each(function (elem) {
            map.geoObjects.remove(elem);
        });

        $.each(routes.points, function (id, point) {
            createConnectionPoint(point.location, id, point.connection);
            var title = point.title ? point.title : "<Не задано>";
            $("#route_from, #route_to").append("<option value='" + id + "'>" + title + "</option>");
        });
        var allLines = []
        $.each(routes.segments, function (id, segment) {
            allLines.push({geometry: [segment.start, segment.end], id: id, title: segment.title});
        });
        var visited = [];
        var lineGroups = [];
        for (var i = allLines.length - 1; i >= 0; i--) {
            if (visited.indexOf(i) > -1) continue;
            var line = allLines[i];
            visited.push(i);
            var conflictingLines = [];
            for (var j = 0; j < i; j++) {
                if (visited.indexOf(j) > -1) continue;
                var aLine = allLines[j];
                if (line.geometry.compare(aLine.geometry) || line.geometry.compare(aLine.geometry.reverse())) {
                    conflictingLines.push(aLine);
                    visited.push(j);
                }
            }
            conflictingLines.push(line);
            lineGroups.push(conflictingLines);
        }
        $.each(lineGroups, function (i, g) {
            (g.length > 1) ? createMultiLine(g) : createLine(g[0].geometry, g[0].id);
        });
    });
}

$.fn.loading = function (state, addClass) {
    var $this = $(this);
    state = state === undefined ? true : !!state;

    $this.each(function (i, element) {

        var $element = $(element);

        if (state && $element.find(".js-loading-overlay").length === 0) {
            var $overlay = $("<div/>").addClass("js-loading-overlay");
            if (addClass !== undefined) {
                $overlay.addClass(addClass);
            }

            $element.append($overlay).addClass("js-loading");
            $overlay.stop().hide().fadeIn("fast");
            $this.find("input,button,.btn").addClass("disabled").prop("disabled", true);
        } else if (!state) {
            $element.removeClass("js-loading").find(".js-loading-overlay").remove();
            $this.find("input,button,.btn").removeClass("disabled").prop("disabled", false);
        }

    });

    return this;

};

function guid() {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g,function (c) {
        var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
        return v.toString(16);
    }).split('-').join("");
}

function bindColorPicker($target, color) {
    if (!color) color = "#000000";
    $target.css("background-color", color);
    $target.ColorPicker({
        color: color,
        onShow: function (colpkr) {
            $(colpkr).fadeIn("fast");
            return false;
        },
        onHide: function (colpkr) {
            $(colpkr).fadeOut("fast");
            return false;
        },
        onChange: function (hsb, hex, rgb) {
            $target.css('backgroundColor', '#' + hex);
            $target.trigger("colorChange");
        }
    });
}

function initRouteDialog() {
    $("#route-edit-form").dialog({
        autoOpen: false,
        height: 200,
        width: 500,
        title: "Новый маршрут",
        draggable: false,
        resizable: false,
        dialogClass: "no-close",
        buttons: {
            "Сохранить маршрут": function () {
                saveRoute();
                $(this).dialog("close");
            },
            "Отмена": function () {
                map.geoObjects.remove(line);
                clearState();
                $(this).dialog("close");
            }
        },
        position: {
            of: "#map"
        },
        open: function (event, ui) {
            $("#map").loading(true);
        },
        close: function () {
            $("#map").loading(false);
        }
    });

}

var theCallback = function (v, s) {
    return v;
};

var numberCallback = function (v, s) {

};

function saveRoute() {
    route["id"] = [];
    route["cable"] = $("#route-cable").val();
    for (var i = 0; i < route["points"].length; i++)
        route["id"].push(guid());
    route["layer"] = $("#mapLayer").val();
    if (route["layer"] == 3) route["layer"] = 1;
    $.ajax({
        url: "include/connection_controller.php",
        type: 'POST',
        data: {
            "op": "save_route",
            "route": JSON.stringify(route)
        }
    }).done(function (msg) {
        var result = JSON.parse(msg);
        if (result.success)
            refreshMap();
        if (!result.success)
            alert("Ошибка при сохранении");
    });

    clearState();
}

function clearState() {
    route = null;
    line = null;
    state = '';
}

function openPointDialog(id, location) {
    var src = "point_form.php" + (id ? ("?id=" + id) : "");
    if (location)
        src = src + (id ? "&" : "?") + "location=" + location;
    src += ((src.indexOf("?") == -1) ? "?" : "&") + "layer=" + $("#mapLayer").val();
    $('#point_container iframe').attr("src", src);
    $("#point_container").dialog("open");
}

function createConnectionPoint(location, id, connection) {
    var imageHref = "images/support.png";
    if (typeof connection != "undefined" && connection != "0")
        imageHref = "images/connect.png";
    var myGeoObject = new ymaps.GeoObject({
        geometry: {
            type: "Point",
            coordinates: location
        }
    }, {
        iconImageSize: [24, 24],
        iconImageOffset: [-12, -12],
        iconImageHref: imageHref,
        zIndex: 15
    });
    myGeoObject.properties.set("pType", "connection");
    myGeoObject.properties.set("connection", (connection ? connection : "0"));
    myGeoObject.properties.set("id", (id ? id : guid()));
    myGeoObject.properties.set("defaultIcon", imageHref);
    myGeoObject.events.add("click", pointClick);

    map.geoObjects.add(myGeoObject);
}

function pointClick(e) {
    var coords = e.get("target").geometry.getCoordinates();
    if (line != null)
        line.geometry.insert(line.geometry.getLength(), coords);
    else if (state == 'edit')
        startPolylineDrawing(coords);
    else if (state != 'move') {
		if ($("#solver-block").is(":visible")) {
        var routeSel = ($("#route_from").val() == 0) ? $("#route_from") : $("#route_to");
        routeSel.val(e.get("target").properties.get("id"));
        routeSel.change();
		}
    }
    else
        openPointDialog(e.get("target").properties.get("id"));

}

function pointDragStart(e) {
    var imageHref = "images/support_transp.png";
    var id = e.get("target").properties.get("id");
    var connect = e.get("target").properties.get("connection");
    if (connect > 0)
        imageHref = "images/connect_transp.png";
    var coords = e.get("target").geometry.getCoordinates();
    var myGeoObject = new ymaps.GeoObject({
        geometry: {
            type: "Point",
            coordinates: coords
        }
    }, {
        iconImageSize: [24, 24],
        iconImageOffset: [-12, -12],
        iconImageHref: imageHref

    });
    if (!movedPoints)
        movedPoints = {};
    if (!movedPoints[id])
        movedPoints[id] = { point: e.get("target"), old: coords };
    map.geoObjects.add(myGeoObject);
    tempPoint = myGeoObject;
}

function pointDragEnd(e) {
    var point = tempPoint.geometry.getCoordinates();
    var after = e.get("target").geometry.getCoordinates();
    updatePointSegments(point, after);
    map.geoObjects.remove(tempPoint);
    tempPoint = null;
}

function updatePointSegments(point, after) {
    map.geoObjects.each(function (obj) {
        if (obj.geometry.getType() != "Point") {
            var coords = obj.geometry.getCoordinates();
            var i = -1;
            if (coords[0].compare(point))
                i = 0;
            else if (coords[1].compare(point))
                i = 1;
            if (i >= 0) {
                coords[i] = after;
                obj.geometry.setCoordinates(coords);
            }
        }
    });
}

function updateNetwork() {
    var data = {};
    $.each(movedPoints, function (idx, obj) {
        var id = obj.point.properties.get("id");
        data[id] = JSON.stringify(obj.point.geometry.getCoordinates());
    });
    $.ajax({
        method: "POST",
        url: "include/connection_controller.php",
        data: {
            op: "update_network",
            data: JSON.stringify(data)
        }
    }).done(function (response) {
        var result = JSON.parse(response);
        if (result.success)
            refreshMap();
        else alert(result.error);
        movedPoints = null;
    });

}

function cancelNetwork() {
    $.each(movedPoints, function (idx, obj) {
        var after = obj.point.geometry.getCoordinates();
        obj.point.geometry.setCoordinates(obj.old);
        updatePointSegments(after, obj.old);
    });
    movedPoints = null;
}

function lineMouseLeave(e) {
    var tempColor = e.get("target").properties.get("tempColor");
    if (tempColor)
        e.get("target").options.set("strokeColor", tempColor);
    else
        e.get("target").options.set("strokeColor", "FF00FFFF");
}

function
    createMultiLine(lines) {
    var properties = {
        "tempColor": false
    }, options = {
        draggable: false,
        strokeColor: '#ff00ff',
        strokeWidth: 4,
        zIndex: 10,
        zIndexHover: 100
    }, polyline = new ymaps.Polyline(lines[0].geometry, properties, options);
    polyline.events.add("mouseenter", function (e) {
        e.get("target").options.set("strokeColor", "0000FFFF");
    });
    polyline.events.add("mouseleave", lineMouseLeave);

    var links = [];
    $.each(lines, function (i, line) {
        links.push($("<a href='javascript:void(0)'>" + line.title + "</a>").attr("onclick", "map.balloon.close(); openSegmentDialog('" + line.id + "')").prop('outerHTML'));
    });
    polyline.properties.set("id", guid());
    polyline.properties.set("lines", lines.map(function (line) {
        return line.id;
    }));

    polyline.events.add("click", function (e) {
        var coords = e.get('coordPosition');
        map.balloon.open(coords, {
            contentBody: links.join("<br/>")
        });
    });
    map.geoObjects.add(polyline);
    var shProperties = {}, shOptions = {
        draggable: false,
        strokeColor: '000000FF',
        strokeWidth: 6,
        zIndex: 5,
        zIndexHover: 5
    };
    var shadow = new ymaps.Polyline(lines[1].geometry, shProperties, shOptions);
    map.geoObjects.add(shadow);
}

function createLine(geometry, id) {
    var properties = {}, options = {
        draggable: false,
        strokeColor: 'ff00ffFF',
        strokeWidth: 4,
        zIndex: 10,
        zIndexHover: 100
    }, polyline = new ymaps.Polyline(geometry, properties, options);

    if (id) {
        polyline.properties.set("id", id);

        polyline.events.add("mouseenter", function (e) {
            e.get("target").options.set("strokeColor", "0000FFFF");
        });
        polyline.events.add("mouseleave", lineMouseLeave);
        polyline.events.add("click", function (e) {
            openSegmentDialog(e.get("target").properties.get("id"));
        });
    }

    map.geoObjects.add(polyline);

    return polyline;
}

function openSegmentDialog(id) {
    var src = "segment_form.php" + (id ? ("?id=" + id) : "");
    $('#segment_container iframe').attr("src", src);
    $("#segment_container").dialog("open");
}

function openConnection(id, cid, create, canSaveConnection) {
    var isCommonSchema = (cid == null && create == false && canSaveConnection == false);
    var src = "connection.php?id=" + id + (cid ? "&cid=" + cid : "") + (create ? "&new=1" : "") + (canSaveConnection ? "&canSaveConnection=1" : "") + (isCommonSchema ? "&isCommonSchema=1" : "");

    var connectionContainer = $("#connection_container");
    connectionContainer.html("<iframe id=\"frmConnectionContainer\" src=\"\" frameborder=\"no\" scrolling=\"no\"></iframe>");
    var frm = $('#connection_container iframe');
    frm.attr("src", src);

    connectionContainer.dialog("open");
}

function addPointHandler(e) {
    map.events.remove('click', addPointHandler);
    cursor.remove();
    state = null;
    openPointDialog(null, "[" + e.get("coords") + "]");
}

function addPointArrayHandler(e) {
    var point = {
        "id": guid(),
        "comment": "",
        "title": "",
        "layer": $("#mapLayer").val(),
        "location": "[" + e.get("coords") + "]",
        "type": $("#point_type_select").val()
    };

    $.ajax({
        method: "POST",
        url: "include/connection_controller.php",
        data: {
            op: "save_point",
            data: JSON.stringify(point)
        }
    }).done(function (response) {
        var result = JSON.parse(response);
        if (!result.success)
            alert("Ошибка при сохранении точки: " + result.error);
        else
            createConnectionPoint(JSON.parse(point.location), point.id);
    });

}

Array.prototype.compare = function (array) {
    // if the other array is a falsy value, return
    if (!array)
        return false;

    // compare lengths - can save a lot of time
    if (this.length != array.length)
        return false;

    for (var i = 0; i < this.length; i++) {
        // Check if we have nested arrays
        if (this[i] instanceof Array && array[i] instanceof Array) {
            // recurse into the nested arrays
            if (!this[i].compare(array[i]))
                return false;
        } else if (this[i] != array[i]) {
            // Warning - two different object instances will never be equal: {x:20} != {x:20}
            return false;
        }
    }
    return true;
}

function getCPColor(target) {
    return '#' + ($('#' + $(target).data('colorpickerId')).data('colorpicker').fields[0].value)

}

function rgb2hex(rgb) {
    rgb = rgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);
    function hex(x) {
        return ("0" + parseInt(x).toString(16)).slice(-2);
    }

    return "#" + hex(rgb[1]) + hex(rgb[2]) + hex(rgb[3]);
}

function union_arrays(x, y) {
    var obj = {};
    for (var i = x.length - 1; i >= 0; --i)
        obj[x[i]] = x[i];
    for (i = y.length - 1; i >= 0; --i)
        obj[y[i]] = y[i];
    var res = []
    for (var k in obj) {
        if (obj.hasOwnProperty(k))  // <-- optional
            res.push(obj[k]);
    }
    return res;
}

function ResizeIframe(frameID) {
    var newwidth;

    var frm = document.getElementById(frameID);
    if (!frm) {
        frm = window.parent.document.getElementById(frameID);
    }

    newwidth = frm.contentWindow.document.body.scrollWidth;

    frm.height = "550px";
    frm.width = (newwidth) + "px";

    return frm;
}

function ResizeConnectionContainerDialog() {
    var frm = ResizeIframe('frmConnectionContainer');
    var dlg = $(frm).closest(".ui-dialog");
    dlg.position({
        of: window.parent.document.body,
        my: "center center",
        at: "center center"
    });
    if (dlg.offset().top < 0)
        dlg.css("top", "0px");
}

function ConvertObjectPropertiesToArray(obj) {
    var arr = [];
    for (var key in obj) {
        if (obj.hasOwnProperty(key)) {
            arr.push(obj[key]);
        }
    }

    return arr;
}

function rememberLocation() {
    $.ajax({
        url: "/include/user_controller.php",
        method: "POST",
        async: false,
        data: {
            op: "settings",
            data: JSON.stringify({
                'id': user_token,
                'location': JSON.stringify(map.getCenter()),
                'zoom': map.getZoom(),
                'layer': $("#mapLayer").val()
            })
        }
    }).done(function (response) {

    });
}

function isInt(value) {
    return !isNaN(value) && parseInt(Number(value)) == value;
}

function IsFloat(value) {
    var val = parseFloat(value);
    if (isNaN(val))
        return false;
    else if (value.toString().indexOf('.') == -1)
        return false;
    else
        return true;
}

function highlightPoint() {
    var id = $(this).val();
    var is_from = $(this).is("#route_from");
    var prevHighlight = is_from ? route_from : route_to;
    if (prevHighlight)
        prevHighlight.options.set("iconImageHref", prevHighlight.properties.get("defaultIcon"));
    if (id == 0 && is_from) route_from = null;
    if (id == 0 && !is_from) route_to = null;
    map.geoObjects.each(function (obj) {
        if (obj.properties.get("id") == id) {
            obj.options.set("iconImageHref", "images/route_point.png");
            obj.options.set("zIndex", 30);
            is_from ? route_from = obj : route_to = obj;
            return false;
        }
    });
}

function solveRoute() {
    var from = $("#route_from").val();
    var to = $("#route_to").val();
    clearRouteHighlight();
    $("#route-info").hide();
    if (!from || !to) {
        alert("Выберите точки");
        return;
    }
    $.ajax({
        method: "POST",
        url: "/solve/solve.php",
        data: {
            "pid": from,
            "target": to
        }
    }).done(function (response) {
        var data = JSON.parse(response);

        if (data.routes.length == 0) {
            alert("Маршрут не найден!");
            return;
        }
        $("#route-info").html(data.markup);
        $("#route-info").show();
        $("#route-info input[name=route]").change(function () {
            clearRouteHighlight();
            var path = data.routes[$(this).val()];
            var ids = [];
            for (var i = 0; i < path.route.length; i++)
                if (path.route[i]["type"] == "segment" || path.route[i]["type"] == "point")
                    ids.push(path.route[i]["id"]);

            highlightedObjects = [];
            map.geoObjects.each(function (obj) {
                // проверка остальных объектов - точек и
                var idInArray = $.inArray(obj.properties.get("id"), ids) > -1;
                var lines = obj.properties.get("lines");
                if (lines) {
                    var intersectedIds = lines.filter(function (n) {
                        return ids.indexOf(n) != -1
                    });
                    idInArray = idInArray || intersectedIds.length > 0;
                }
                if (!idInArray) return;

                if (obj.geometry.getType() == "Point")
                    obj.options.set("iconImageHref", "images/route_point.png");
                else {
                    obj.properties.set("tempColor", "ede22fFF");
                    obj.options.set("strokeColor", "ede22fFF");
                }
                highlightedObjects.push(obj);
            });
        });
		
        $("#route-info .route-details").click(function () {
            var path = data.routes[$(this).data("id")];
            var infoDiv = $("#route-details .route-path");
            infoDiv.html("");
            var routeList = $("<ol class='route-list'></ol>");
            var plotData = [];
            var currentPlotData = [0, 0];
            for (var i = 0; i < path.route.length; i++) {
                var hop = path.route[i];
                var li = $("<li></li>");
                if (hop.type == "point") {
                    li.append("<b>Точка: " + hop.title + "</b><br/>")
                        .append("Координаты: " + hop.location + "<br/>");
                    if (hop.welding > 0) {
                        li.append("Затухание сварки: " + hop.welding.toFixed(2) + " дб<br/>");
                        plotData.push(currentPlotData);
                        currentPlotData = [currentPlotData[0], currentPlotData[1] + hop.welding];
                    }
                }
                else if (hop.type == "segment") {
                    li.append("<b>Сегмент: " + hop.data.title + "</b><br/>")
                        .append("Длина: " + (hop.data.length * 1000).toFixed(2) + " м<br/>")
                        .append("Затухание: " + hop.data.attenuation.toFixed(2) + " дб<br/>");
                    plotData.push(currentPlotData);
                    currentPlotData = [currentPlotData[0] + hop.data.length * 1000, currentPlotData[1] + hop.data.attenuation];
                }
                else {
                    li.append("<b>Сплиттер</b><br/>")
                        .append((hop.data.direct ? "Вход " : "Выход ") + hop.data.input + " -> " +
                            (hop.data.direct ? "Выход " : "Вход ") + hop.data.output + "<br/>")
                        .append("Затухание: " + hop.data.attenuation + " дб<br/>");
                    plotData.push(currentPlotData);
                    currentPlotData = [currentPlotData[0], currentPlotData[1] + hop.data.attenuation];
                }
                routeList.append(li);
            }
            plotData.push(currentPlotData);
            $.plot($(".route-plot"), [plotData], {
                    grid: {
                        margin: {
                            left: 40
                        },
                        labelMargin: 10
                    },
                    axisLabels: {
                        show: true
                    },
                    xaxes: [{
                        axisLabel: 'Расстояние, м',
                        axisLabelPadding: 12
                    }],
                    yaxes: [{
                        position: 'left',
                        axisLabel: 'Затухание, Дб'
                    }]
                }
            );
            infoDiv.append(routeList);
            $("#route-details").dialog("open");
        });
		$(".route-toggle-all").click(function() {
			$(".additional").toggle();
		});
        $("#route-info input:checked").change();
    });
}

function clearRouteHighlight() {
    if (!highlightedObjects) return;
    var from_id = route_from ? route_from.properties.get("id") : null;
    var to_id = route_to ? route_to.properties.get("id") : null;
    for (var i = 0; i < highlightedObjects.length; i++) {
        var obj = highlightedObjects[i]
        var id = obj.properties.get("id");

        if (obj.geometry.getType() == "Point" && id != from_id && id != to_id)
            obj.options.set("iconImageHref", obj.properties.get("defaultIcon"));
        else {
            obj.options.set("strokeColor", "FF00FFFF");
            obj.properties.set("tempColor", null);
        }
    }
    highlightedObjects = null;
}

function clearRoute() {
    $("#route-info").hide();
    $("#route_from, #route_to").val(0);
    $("#route_from, #route_to").change();
    clearRouteHighlight();
}